package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
)

const (
	ActionRegister string = "register"
	ActionGPS      string = "gps"
	ActionAlarm    string = "alarm"
	ActionDeal     string = "deal"
)

type MonitorConn struct {
	conn           *websocket.Conn
	dbo            *DBOperation
	checkAccessUrl string

	userid   string
	userType int
	cid      int
	teamId   string
	language string
	gpsType  string

	exitChan chan bool
	sendChan chan interface{}
	tr       *http.Transport
}

func NewMonitorConn(conn *websocket.Conn, dbo *DBOperation, cau string) *MonitorConn {
	mc := MonitorConn{conn: conn, dbo: dbo, checkAccessUrl: cau}
	mc.exitChan = make(chan bool)
	mc.sendChan = make(chan interface{}, 10)
	mc.tr = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	return &mc
}

func (p *MonitorConn) HasReceiver(rid string) bool {
	if p.userType == UserTypeSystemUser {
		return true
	} else if p.userType == UserTypeAdministrator {
		return p.dbo.companyHasReceiver(p.cid, rid)
	} else if p.userType == UserTypeTeamLeader {
		return p.dbo.teamHasReceiver(p.teamId, rid)
	} else if p.userType == UserTypeIndividual || p.userType == UserTypeDriver {
		return p.dbo.userHasReceiver(p.userid, rid)
	} else {
		return false
	}
}

func (p *MonitorConn) SetUserId(userid string) {
	p.userid = userid
	ct, err := p.dbo.userInfo(userid)
	if err == nil {
		p.userType = ct.Utype
		p.cid = ct.Cid
		p.teamId = ct.Tid
	}
}

func (p *MonitorConn) Run() {
	var action string

	go p.SendProcess()

	for {
		var v map[string]interface{}
		err := p.conn.ReadJSON(&v)
		if err == nil {
			zLog(nil, p.conn.RemoteAddr().String(), "收到数据：", v)
			action = v["action"].(string)
			if action == ActionRegister {
				err = p.handleRegister(v)
			} else {
				err = errors.New("非法访问")
			}
			if err != nil {
				er := ErrorReturn{ErrCode: 1006, Error: "非法访问"}
				p.conn.WriteJSON(er)
				p.exitChan <- true
				return
			}
		} else {
			p.exitChan <- true
			return
		}
	}
}

func (p *MonitorConn) SendProcess() {
	zLog(nil, "发送协程启动")
	defer func() {
		//if err := recover(); err != nil {
		// `zLog(nil, "SendProcess异常：", err)
		close(p.sendChan)
		zLog(nil, "发送协程退出")
		//}
	}()

	var err error
	for {
		select {
		case <-p.exitChan:
			return
		case v := <-p.sendChan:
			err = p.conn.WriteJSON(v)
			if err != nil {
				zLog(nil, "发送数据给", p.conn.RemoteAddr().String(), "失败，数据：", v, "；错误：", err)
			} else {
				zLog(nil, "发送数据给", p.conn.RemoteAddr().String(), "成功，数据为：", v)
			}
		}
	}
}

func (p *MonitorConn) handleRegister(v map[string]interface{}) error {
	if p.userid != "" {
		return nil
	}

	var er ErrorReturn

	userid := v["userid"].(string)
	token := v["accesstoken"].(string)
	if userid == "" || token == "" {
		er.ErrCode = 1006
		er.Error = "非法访问"
		//p.conn.WriteJSON(er)
		return errors.New(er.Error)
	}

	//if p.dbo.checkAccessToken(userid, token) {
	if p.checckAccessToken(userid, token) {
		p.SetUserId(userid)
		p.language = v["language"].(string)
		if p.language == "" {
			p.language = "cn"
		}
		p.gpsType = v["gpstype"].(string)
		if p.gpsType == "" {
			p.gpsType = GpsBd09
		}
		p.conn.WriteMessage(websocket.TextMessage, []byte(`{"errcode": 0}`))
	} else {
		er.ErrCode = 1006
		er.Error = "非法访问"
		//p.conn.WriteJSON(er)
		return errors.New(er.Error)
	}

	return nil
}

type ErrorReturn struct {
	ErrCode int    `json:"errcode"`
	Error   string `json:"error"`
}

func (p *MonitorConn) checckAccessToken(userid, token string) bool {
	type Result struct {
		ErrCode int    `json:"errcode"` //`json: "errcode"`
		Msg     string `json:"msg"`
	}

	sUrl := fmt.Sprintf(p.checkAccessUrl+"checkaccess?userid=%s&accesstoken=%s", userid, token)
	c := http.Client{
		Transport: p.tr,
	}
	resp, err := c.Get(sUrl)
	if err != nil {
		return false
	}

	defer resp.Body.Close()
	buf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return false
	}

	var res Result
	err = json.Unmarshal(buf, &res)
	if err != nil {
		return false
	}

	return res.ErrCode == 0
}
